package com.ocm.core.domain;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.OneToOne;
import javax.persistence.Table;
import javax.persistence.TableGenerator;

import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.GrantedAuthorityImpl;

@Entity
@Table(name = "USERDETAIL")
@NamedQueries( {
   @NamedQuery(name = UserDetail.FIND_ALL, query = "SELECT userdetail FROM UserDetail userdetail where userdetail.type=:type"),
   @NamedQuery(name = UserDetail.FIND_NAME, query = "SELECT userdetail FROM UserDetail userdetail WHERE LOWER(userdetail.username)=LOWER(:name) and userdetail.type=:type"),
   @NamedQuery(name = UserDetail.FIND_LIKENAME_TYPE, query = "SELECT userdetail FROM UserDetail userdetail WHERE LOWER(userdetail.username) LIKE (:name) and userdetail.type =:type"),
   @NamedQuery(name = UserDetail.FIND_LIKENAME, query = "SELECT userdetail FROM UserDetail userdetail WHERE LOWER(userdetail.username) LIKE (:name) and userdetail.type IN (:type)"),
   @NamedQuery(name = UserDetail.FIND_NAMEs, query = "SELECT userdetail FROM UserDetail userdetail WHERE LOWER(userdetail.username) IN (LOWER(:name)) and userdetail.type IN (:type)"),
   @NamedQuery(name = UserDetail.FIND_IDs, query = "SELECT userdetail FROM UserDetail userdetail WHERE userdetail.id IN (:ids)"),
   @NamedQuery(name = UserDetail.FIND_BY_GROUPIDS_USERID, query = "SELECT g FROM UserDetail u left join u.userDetails g WHERE g.id IN (:ids) and u.id =:userid")})
public class UserDetail implements Persistable {

   public static final String FIND_ALL = "UserDetail.FIND_ALL";

   public static final String FIND_NAME = "UserDetail.FIND_NAME";

   public static final String FIND_NAMEs = "UserDetail.FIND_NAMEs";

   public static final String FIND_LIKENAME = "UserDetail.FIND_LIKENAME";

   public static final String FIND_LIKENAME_TYPE = "UserDetail.FIND_LIKENAME_TYPE";

   public static final String FIND_IDs = "UserDetail.FIND_IDs";

   public static final String FIND_BY_GROUPIDS_USERID = "UserDetail.FIND_BY_GROUPIDs_USERID";

   public static final String PARA_NAME = "name";

   public static final String PARA_IDs = "ids";

   public static final String PARA_USERID = "userid";

   public static final String PARA_TYPE = "type";

   @Id
   @GeneratedValue(strategy = GenerationType.TABLE, generator = "GEN_USERDETAIL")
   @TableGenerator(name = "GEN_USERDETAIL", table = "SEQUENCE_LIST", allocationSize = 1, initialValue = 1, pkColumnName = "NAME", valueColumnName = "NEXT_SEQUENCE", pkColumnValue = "USERDETAIL")
   @Column(name = "USERDETAIL_ID")
   private Long id;

   @Column(name="USERNAME", nullable=false)
   private String username;

   @Column(name="NONDISABLE", nullable=false)
   private Boolean isEnabled;

   @Column(name="CREADENTIALSNONEXPIRED", nullable=false)
   private Boolean isCredentialsNonExpired;

   @Column(name="AUTHORITY", nullable=false)
   private String authority;

   @Column(name="TYPE", nullable=false)
   @Enumerated(EnumType.ORDINAL)
   private UserDetailType type;

   @Column(name="ISUSERSYSTEM")
   private Boolean isUserSystem;

   @OneToOne(cascade=CascadeType.ALL)
   @JoinColumn(name="USERINFO_ID")
   private UserInfo userInfo;

   @ManyToMany(cascade = CascadeType.ALL)
   @JoinTable(name = "GROUP_USER", joinColumns = @JoinColumn(name = "GROUP_USER_ID", referencedColumnName = "USERDETAIL_ID"), 
      inverseJoinColumns = @JoinColumn(name = "USER_GROUP_ID", referencedColumnName = "USERDETAIL_ID"))
   private Set<UserDetail> userDetails;

   public Collection<GrantedAuthority> getAuthorities() {
      String[] authoritiesArray = this.authority.split(",");
      Collection<GrantedAuthority> grantedAuthorities = new ArrayList<GrantedAuthority>();
      for (String authorityName : authoritiesArray){
         grantedAuthorities.add(new GrantedAuthorityImpl(authorityName));
      }
      return grantedAuthorities;
   }

   public String getAuthority() {
      return authority;
   }

   public void setAuthority(String authority) {
      this.authority = authority;
   }

   public UserDetail() {
      userDetails = new HashSet<UserDetail>();
   }

   public UserInfo getUserInfo() {
      return userInfo;
   }

   public void setUserInfo(UserInfo userInfo) {
      this.userInfo = userInfo;
   }

   public Long getId() {
      return id;
   }

   public void setId(Long id) {
      this.id = id;
   }

   public String getPassword() {
      if (userInfo == null)
         return "";
      return userInfo.getPassword();
   }

   public String getUsername() {
      return username;
   }

   public boolean isAccountNonExpired() {
      if (userInfo == null)
         return this.isEnabled;
      return userInfo.isAccountNonExpired();
   }

   public boolean isAccountNonLocked() {
      if (userInfo == null)
         return this.isEnabled;
      return userInfo.getIsAccountNonLocked();
   }

   public boolean isCredentialsNonExpired() {
      return isCredentialsNonExpired;
   }

   public boolean isEnabled() {
      return isEnabled;
   }

   public UserDetailType getType() {
      return type;
   }

   public void setType(UserDetailType type) {
      this.type = type;
   }

   public List<UserDetail> getUserDetails() {
      List<UserDetail> userDetails  = new ArrayList<UserDetail>(this.userDetails);
      return userDetails;
   }

   public void setUserDetails(List<UserDetail> userDetails) {
      this.userDetails.clear();
      this.userDetails.addAll(userDetails);
   }

   public void setUsername(String username) {
      this.username = username;
   }

   public void setIsCredentialsNonExpired(Boolean isCredentialsNonExpired) {
      this.isCredentialsNonExpired = isCredentialsNonExpired;
   }

   public Boolean getIsEnabled() {
      return isEnabled;
   }

   public void setIsEnabled(Boolean isEnabled) {
      this.isEnabled = isEnabled;
   }

   public Boolean getIsUserSystem() {
      return isUserSystem;
   }

   public void setIsUserSystem(Boolean isUserSystem) {
      this.isUserSystem = isUserSystem;
   }
}
